﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Color = System.Drawing.Color;

namespace MicroLED_Detecter
{
    public partial class FormSpectrometer : Form
    {
        public Spectrometer spectrometer = new Spectrometer();
        int flag_IsSpectrometerConnected = 0;// 光谱仪是否被连接
        // int pixelNum = 2048;// 像素数(可以调用函数获取，这里看说明书为2048)
        // 波长数据
        double[] wlArray = new double[2048];
        // 光谱能量数据
        double[] spArray = new double[2048];
        // 校正后的光谱能量
        double[] spArrayCal = new double[2048];
        // 辐射通量
        double fsw = 0.0;
        string ExcelSaveFoldPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);// 光谱数据默认保存路径：桌面
        // 观察者函数
        static double[] CIEWaveArr = new double[401];
        static double[] CIEXArr = new double[401];
        static double[] CIEYArr = new double[401];
        static double[] CIEZArr = new double[401];
        public FormSpectrometer()
        {
            InitializeComponent();
        }

        private void FormSpectrometer_FormClosing(object sender, FormClosingEventArgs e)
        {
            ((FormMain)Owner).Toggletsb_Spectrometer(true);//只能打开一个FormSpectrometer
        }

        private void btn_ConnectSpectrometer_Click(object sender, EventArgs e)// 连接光谱仪
        {
            if (flag_IsSpectrometerConnected == 1)
                return;

            int ret = spectrometer.ConnectSpectrometer();
            if (ret == 0)
            {
                flag_IsSpectrometerConnected = 1;
                tssl_IsSpectrometerConnected.Text = "光谱仪已连接   ";
                tssl_IsSpectrometerConnected.ForeColor = Color.Green;

                SaveParameters(int.Parse(tbx_InitTime.Text), int.Parse(tbx_BCW.Text), int.Parse(tbx_STA.Text));
            }
        }

        private void btn_DisconnectSpectrometer_Click(object sender, EventArgs e)// 断开光谱仪
        {
            if (flag_IsSpectrometerConnected == 0)
                return;

            int ret = spectrometer.DisconnectSpectrometer();
            if(ret == 1)
            {
                flag_IsSpectrometerConnected = 0;
                tssl_IsSpectrometerConnected.Text = "光谱仪未连接   ";
                tssl_IsSpectrometerConnected.ForeColor = Color.Red;
            }
        }

        private void SaveParameters(int initTime, int BCW, int STA)// 设置光谱仪参数
        {
            int ret1 = spectrometer.SetIntTime(initTime); // 设置积分时间单位是毫秒
            int ret2 = spectrometer.SetBCW(BCW);  // 设置平滑宽度
            int ret3 = spectrometer.SetSTA(STA); // 设置采样次数
            //pixelNum = spectrometer.GetPixelCount(0); // 获取像素点数量
            if (ret1 == 1 && ret2 == 1 && ret3 == 1)
                MessageBox.Show("参数设置成功");

            tssl_Parameters.Text = "积分时间:" + initTime.ToString() + "ms | 平滑宽度:" + BCW.ToString() + " | 采样次数:" + STA.ToString() + "   ";
        }

        private void btn_SaveSpectrometerParameters_Click(object sender, EventArgs e)
        {
            if (flag_IsSpectrometerConnected == 0)
                return;

            if (int.Parse(tbx_InitTime.Text) <= 0 || int.Parse(tbx_InitTime.Text) > 10000)
            {
                MessageBox.Show("积分时间在[1,10000]ms之间且为整数！");
                return;
            }

            if (int.Parse(tbx_BCW.Text) < 0 || int.Parse(tbx_BCW.Text) > 100)
            {
                MessageBox.Show("平滑宽度在[0,100]之间且为整数！");
                return;
            }

            if (int.Parse(tbx_STA.Text) < 0 || int.Parse(tbx_STA.Text) > 100)
            {
                MessageBox.Show("采样次数在[0,100]之间且为整数！");
                return;
            }

            SaveParameters(int.Parse(tbx_InitTime.Text), int.Parse(tbx_BCW.Text), int.Parse(tbx_STA.Text));
        }

        private void btn_SpectrometerScan_Click(object sender, EventArgs e) // 扫描，获取光谱
        {
            if(flag_IsSpectrometerConnected == 0)
                return;

            spectrometer.GetWaveLength(0, ref wlArray); // 读取波长数据
            spectrometer.DoScan(); // 测量光谱
            spectrometer.GetSpectrum(ref spArray); // 读取光谱数据
            for (int i = 0; i < 2048; i++)
                wlArray[i] = Math.Round(wlArray[i], 1);// 波长保留1位小数
            chart_Spec.Series["Series1"].Points.DataBindXY(wlArray, spArray);   // 初始光谱

            // 读取cal校正文件
            FileStream fs = new FileStream("data\\20230223.cal", FileMode.Open);
            StreamReader sw = new StreamReader(fs);
            for (int i = 0; i < 1; i++)
            {
                sw.ReadLine();  // 前面没用的数据
            }
            string s;
            int idx = 0;
            while ((s = sw.ReadLine()) != null)
            {
                double num = double.Parse(s.Trim());
                spArrayCal[idx] = spArray[idx] * num;
                idx++;
            }
            chart_Spec.Series["Series2"].Points.DataBindXY(wlArray, spArrayCal);   // 校正光谱
            sw.Close();
            fs.Close();

            // 处理数据
            CalculateSpec();
        }

        private void CalculateSpec()
        {
            // 生成数据表
            dgv_Spec.Rows.Clear();
            for (int i = 0; i < wlArray.Length; i++)
            {
                DataGridViewRow row = new DataGridViewRow();
                row.CreateCells(dgv_Spec);
                row.Cells[0].Value = (i + 1).ToString("#0000");
                row.Cells[1].Value = wlArray[i].ToString("#0.00");
                row.Cells[2].Value = spArray[i].ToString("#0.00");
                row.Cells[3].Value = spArrayCal[i].ToString();
                dgv_Spec.Rows.Add(row);
            }

            // 计算辐射通量
            fsw = 0.0;
            for (int i = 1; i < 2048; i++)
            {
                fsw += (wlArray[i] - wlArray[i - 1]) * spArrayCal[i];
            }
            tbx_fsw.Text = Math.Round(fsw, 4).ToString();

            // 计算峰值光谱、光谱范围与能量范围
            double minWave = 99999, maxWave = 0.0, minPower = 99999;
            double maxPowerWave = 0.0, maxPower = 0.0;
            int maxIdx = 0;
            for (int i = 0; i < 2048; i++)
            {
                minPower = Math.Min(minPower, spArrayCal[i]);
                minWave = Math.Min(minWave, wlArray[i]);
                maxWave = Math.Max(maxWave, wlArray[i]);
                if (spArrayCal[i] > maxPower)
                {
                    maxPower = spArrayCal[i];
                    maxPowerWave = wlArray[i];
                    maxIdx = i;
                }
            }
            tbx_peak.Text = maxPowerWave.ToString("#0.00");
            tbx_waveRange.Text = minWave.ToString("#0.00") + "-" + maxWave.ToString("#0.00");
            tbx_powerRange.Text = minPower.ToString("#0.00") + "-" + maxPower.ToString("#0.00");
            tbx_dataCnt.Text = wlArray.Length.ToString();

            // 计算半峰宽(仅针对最高峰)
            int left = maxIdx, right = maxIdx;
            while (left >= 0 && spArrayCal[left] > 0.5 * maxPower) --left;
            while (right < wlArray.Length && spArrayCal[right] > 0.5 * maxPower) ++right;
            double fwhm = wlArray[right - 1] - wlArray[left];
            tbx_FWHM.Text = fwhm.ToString("#0.00");

            // 计算色坐标
            // 首先对光谱数据进行插值，求出380-780nm中的每个点
            // 要求光谱范围必须覆盖380-780nm,这个区间
            //if (waveList[0] > 380 || waveList[waveList.Count - 1] < 780)
            //{
            //    MessageBox.Show("请提供涵盖380-780nm的光谱", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
            //    return;
            //}
            double[] powerLinear = new double[401];
            int idx = 0;
            for (int i = 0; i < wlArray.Length - 1; i++)
            {
                if (idx < 401 && wlArray[i] <= CIEWaveArr[idx] && wlArray[i + 1] >= CIEWaveArr[idx])
                {
                    powerLinear[idx] = spArrayCal[i] + ((CIEWaveArr[idx] - wlArray[i]) * (spArrayCal[i + 1] - spArrayCal[i])) / (wlArray[i + 1] - wlArray[i]);
                    ++idx;
                }
            }
            // 积分
            double X = 0.0, Y = 0.0, Z = 0.0;
            for (int i = 0; i < 401; i++)
            {
                X += powerLinear[i] * CIEXArr[i];
                Y += powerLinear[i] * CIEYArr[i];
                Z += powerLinear[i] * CIEZArr[i];
            }
            double x = X / (X + Y + Z), y = Y / (X + Y + Z);

            tbx_ciex.Text = x.ToString("#0.00");
            tbx_ciey.Text = y.ToString("#0.00");

            // 绘制CIE色坐标图
            chart_CIE.Series["Series1"].Points.AddXY(x, y);

            // 转化为CCT
            double cct = CalculateCCT(x, y);
            tbx_cct.Text = cct.ToString("#0");
        }
        public static double CalculateCCT(double x, double y)   // 计算CCT Robert法
        {
            double xe = 0.3320;
            double ye = 0.1858;
            double t, n;

            // Calculate the inverse slope and inverse intercept
            n = (x - xe) / (y - ye);
            t = 449.0 * Math.Pow(n, 3) + 3525.0 * Math.Pow(n, 2) + 6823.3 * n + 5520.33;

            return t;
        }

        private void btn_clearCIE_Click(object sender, EventArgs e)
        {
            chart_CIE.Series["Series1"].Points.Clear();
        }

        private void FormSpectrometer_Load(object sender, EventArgs e)
        {
            label_ExcelSavePath.Text = "保存路径：" + Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

            // 加载CIE观察者函数V(λ)
            string fileName = "data\\CIE.txt";
            if (!File.Exists(fileName)) return;
            using (StreamReader sr = new StreamReader(fileName))
            {
                string line;
                int idx = 0;
                while ((line = sr.ReadLine()) != null)
                {
                    double waveLen = 0.0, cieX = 0.0, cieY = 0.0, cieZ = 0.0;
                    if (line.Split(' ').Length != 4 || !double.TryParse(line.Split(' ')[0], out waveLen) || !double.TryParse(line.Split(' ')[1], out cieX) ||
                        !double.TryParse(line.Split(' ')[2], out cieY) || !double.TryParse(line.Split(' ')[3], out cieZ))
                    {
                        MessageBox.Show("CIE数据有误", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    CIEWaveArr[idx] = waveLen;
                    CIEXArr[idx] = cieX;
                    CIEYArr[idx] = cieY;
                    CIEZArr[idx] = cieZ;
                    ++idx;
                }
            }
        }

        private void btn_SetExcelSavePath_Click(object sender, EventArgs e) // 更改保存路径
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                ExcelSaveFoldPath = folderBrowserDialog.SelectedPath;
                label_ExcelSavePath.Text = "保存路径：" + folderBrowserDialog.SelectedPath;
            }
        }

        private void btn_exportExcel_Click(object sender, EventArgs e)// 导出光谱数据Excel文件
        {
            string ExcelSavePath = ExcelSaveFoldPath + "\\" + DateTime.Now.ToString("yyyy.MM.dd_HH.mm.ss") + "_spectrum_test.xlsx";
            using (SpreadsheetDocument document = SpreadsheetDocument.Create(ExcelSavePath, SpreadsheetDocumentType.Workbook))
            {
                WorkbookPart workbookPart = document.AddWorkbookPart();
                workbookPart.Workbook = new Workbook();

                WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
                worksheetPart.Worksheet = new Worksheet(new SheetData());

                Sheets sheets = document.WorkbookPart.Workbook.AppendChild(new Sheets());
                Sheet sheet = new Sheet()
                {
                    Id = document.WorkbookPart.GetIdOfPart(worksheetPart),
                    SheetId = 1,
                    Name = "Sheet1"
                };
                sheets.Append(sheet);

                // 获取列标题
                Row headerRow = new Row();
                foreach (DataGridViewColumn column in dgv_Spec.Columns)
                {
                    headerRow.AppendChild(CreateTextCell(column.HeaderText));
                }

                SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
                sheetData.AppendChild(headerRow);

                // 添加行数据
                foreach (DataGridViewRow row in dgv_Spec.Rows)
                {
                    Row newRow = new Row();
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        newRow.AppendChild(CreateTextCell(cell.Value?.ToString() ?? ""));
                    }
                    sheetData.AppendChild(newRow);
                }
            }

            MessageBox.Show("已保存光谱数据Excel文件");
        }
        private Cell CreateTextCell(string text)
        {
            Cell cell = new Cell(new InlineString(new Text(text)));
            cell.DataType = CellValues.InlineString;
            return cell;
        }
    }
}
